/*
 * This file is part of LangMan.
 *
 * LangMan is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * LangMan is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LangMan.  If not, see <http://www.gnu.org/licenses/>.
 */

package langman.business.profiles;

import com.mycila.xmltool.XMLDoc;
import com.mycila.xmltool.XMLTag;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyListWrapper;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import langman.business.data.TranslationException;
import langman.util.GeneralUtils;
import langman.util.doping.Inject;
import langman.util.doping.SingletonBean;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

import static com.google.common.base.Preconditions.checkNotNull;

@SingletonBean
public class ProfileService {
    public static final String NAME_ATTRIBUTE = "name";
    public static final String ROOT_FOLDER_ATTRIBUTE = "rootFolder";
    public static final String CONFIG_FILE_ATTRIBUTE = "configFile";
    public static final String PROFILE_TAG = "profile";
    public static final String ROOT_TAG = "profiles";
    private ObservableList<Profile> profiles = FXCollections.observableArrayList();
    private ObjectProperty<Profile> selectedProfile = new SimpleObjectProperty<>();

    @Inject
    public void initProfileFile() throws TranslationException {
        File profileFile = determineProfileFile();

        if (profileFile.exists()) {
            readProfiles(profileFile);
        } else {
            writeProfileFile(profileFile);
        }
    }

    public void writeProfileFile() throws TranslationException {
        File profileFile = determineProfileFile();
        writeProfileFile(profileFile);
    }

    private void writeProfileFile(File profileFile) throws TranslationException {
        try {
            if (!profileFile.exists()) {
                Files.createFile(profileFile.toPath());
            }
        } catch (IOException e) {
            throw new TranslationException(e);
        }

        XMLTag xmlTag = XMLDoc.newDocument(true).addRoot(ROOT_TAG);

        for (Profile profile : profiles) {
            XMLTag profileTag = xmlTag.addTag(PROFILE_TAG);
            profileTag.addAttribute(NAME_ATTRIBUTE, profile.getProfileName());
            profileTag.addAttribute(ROOT_FOLDER_ATTRIBUTE, profile.getRootFolder().getAbsolutePath());
            profileTag.addAttribute(CONFIG_FILE_ATTRIBUTE, profile.getConfigFile().getAbsolutePath());
            xmlTag.gotoParent();
        }

        try {
            Files.write(profileFile.toPath(), xmlTag.toBytes());
        } catch (IOException e) {
            throw new TranslationException(e);
        }
    }

    private void readProfiles(File profileFile) {
        XMLTag xmlDoc = XMLDoc.from(profileFile, true);
        Iterable<XMLTag> profileTags = xmlDoc.getChilds(PROFILE_TAG);
        for (XMLTag profileTag : profileTags) {
            String name = profileTag.getAttribute(NAME_ATTRIBUTE);
            File rootFolder = new File(profileTag.getAttribute(ROOT_FOLDER_ATTRIBUTE));
            File configFile = new File(profileTag.getAttribute(CONFIG_FILE_ATTRIBUTE));

            Profile profile = new Profile(name, rootFolder, configFile);
            profiles.add(profile);
        }
    }

    public ObservableList<Profile> getProfilesUnmodifiable() {
        return new ReadOnlyListWrapper<>(profiles);
    }

    public void addProfile(Profile profile) throws TranslationException {
        profiles.add(profile);
        writeProfileFile(determineProfileFile());
    }

    public void removeProfile(Profile profile) throws TranslationException {
        profiles.remove(profile);
        writeProfileFile(determineProfileFile());
    }

    private File determineProfileFile() throws TranslationException {
        File userDir = GeneralUtils.getUserDir();

        if (userDir == null || !userDir.isDirectory() || !userDir.canRead()) {
            throw new TranslationException("User dir " + userDir + " is not accesible!");
        }

        File appfolder = new File(userDir, "langman");
        try {
            Files.createDirectories(appfolder.toPath());
        } catch (IOException e) {
            throw new TranslationException(e);
        }

        return new File(appfolder, "profile.xml");
    }

    public void setSelectedProfile(Profile profile) {
        checkNotNull(profile);
        selectedProfile.set(profile);
    }

    public Profile getSelectedProfile() {
        return selectedProfile.get();
    }
}